#ifndef N1SMARTBUFFER_2009_11_03
#define N1SMARTBUFFER_2009_11_03

#include "N0Lib.h"
#include "N1Memory.h"
#include "N1Math.h"

class N1SmartBuffer {
public:
    N1SmartBuffer() : m_ptr(NULL), m_dataSize(0), m_bufferSize(0) { };
    N1SmartBuffer(char* ptr, uint32 size) : m_ptr(ptr), m_dataSize(size), m_bufferSize(0) { };
    N1SmartBuffer(uint32 capacity) : m_ptr(NULL), m_dataSize(0), m_bufferSize(0)
    { 
        setBufferSize(capacity);
    };
    ~N1SmartBuffer() { free(); };

    bool   isOwnBuffer()   const { return m_bufferSize; };
    uint32 getBufferSize() const { return m_bufferSize; };
    uint32 getDataSize()   const { return m_dataSize;   };
    const char*  getPtr()  const { return m_ptr; };
    char*  getPtr()              { return m_ptr; };

    template<typename T>
    operator T() { return static_cast<T>(m_ptr); };

    void attach(void* data, uint32 size)
    {
        free();

        m_ptr = static_cast<char*>(data);
        m_dataSize = m_bufferSize = size;
    };

    void detach()
    {
        m_ptr = NULL;
        m_dataSize = m_bufferSize = 0;
    }

    void setBufferSize(uint32 newSize) 
    { 
        if(newSize==m_bufferSize) return;
        char* ptr = (char*)N1Malloc(newSize);
        if(m_ptr)
        {
            memcpy(ptr, m_ptr, N1Min(newSize, m_dataSize));
            N1Free(m_ptr);
        }
        m_ptr = ptr;
        m_bufferSize = newSize;
        if(m_bufferSize<m_dataSize)
            m_dataSize = m_bufferSize;
    };

    void appendData(uint32 bytes)
    {
        if(m_dataSize + bytes <= m_bufferSize) return;
        uint32 newBufferSize = N1GetNewSizeByLog2(m_bufferSize, 
                                                  m_dataSize + bytes - m_bufferSize, 
                                                  sizeof(void*));
        m_dataSize += bytes;
        setBufferSize(newBufferSize);
    };

    void free()
    {
        if(m_bufferSize && m_ptr) 
        {
            N1Free(m_ptr);
        }
    };

protected:
    char*      m_ptr;
    N1UInt32   m_dataSize;
    N1UInt32   m_bufferSize;

private:
    N1SmartBuffer(const N1SmartBuffer& b);
    N1SmartBuffer& operator=(const N1SmartBuffer& b);
};

#endif //N1SMARTBUFFER_2009_11_03
